Skip to content

Document 0.5.0#4

Merged
sascha-egerer merged 17 commits into
mainfrom
feature/0.5.0-docs
Jun 9, 2026
Merged

Document 0.5.0#4
sascha-egerer merged 17 commits into
mainfrom
feature/0.5.0-docs

Conversation

@sascha-egerer

Copy link
Copy Markdown
Contributor
  • portable config
  • composition
  • presets + proxy/IP
  • PSR-16
  • RequestContext
  • some fixes

Document the now-optional rule key defaulting to the client IP across the
throttle/fail2ban/allow2ban/track pages. Fix the evaluation order
(Fail2Ban then Throttle then Allow2Ban) on the rate-limiting, bot-detection
and fail2ban pages. Broaden the PortableConfig safelist header-filter
rejection to the whole header_ family, correct the observability
FirewallResult example, and tidy the Slim, Mezzio, TYPO3 and storage
integration notes.
Shorten the Presets & Portable Config blurb to match the others and add a
Flexible Storage card so the grid is an even 4+4 instead of 4+3.
The rule key now defaults to the client IP, so examples that passed
key: KeyExtractors::ip() (the REMOTE_ADDR default) just carried boilerplate.
Omit it across the throttle/fail2ban/allow2ban/track examples. The complete
setups that configure a trusted-proxy resolver now correctly key on the
resolved client IP instead of forcing REMOTE_ADDR, and their comments are
corrected accordingly. Explicit keys are kept only where the key is not the
client IP (header, username, path-scoped closures).
…extension

The hand-rolled middleware wiring was redundant and easy to get wrong. The
official flowd/typo3-firewall extension registers Phirewall's PSR-15
middleware in the frontend stack and adds a backend module, so the TYPO3
section now just recommends it.
Replace the npm package-lock.json with pnpm-lock.yaml and pnpm-workspace.yaml,
and bump vitepress to 2.0.0-alpha.17.
config/system/phirewall.php must return a closure that receives the PSR-14
EventDispatcherInterface and returns a built Config (cache first, dispatcher
second). Add a minimal example.
Rate-limit, fail2ban and allow2ban examples now key on the client IP (the
default) instead of forgeable request headers like X-User-Id / X-Api-Key,
which a caller can rotate or drop to evade the limit. The KeyExtractors
reference table and the "header keys are client-controlled" warnings stay.
@sascha-egerer sascha-egerer force-pushed the feature/0.5.0-docs branch 2 times, most recently from 0ce8425 to d8342be Compare June 8, 2026 21:57
@sascha-egerer sascha-egerer force-pushed the feature/0.5.0-docs branch 2 times, most recently from 35e81ec to 3e74d89 Compare June 9, 2026 05:55
Apply a specialist review pass over the docs site:

- Correct the trusted-proxy resolver description (flattened chain plus
  trusted-peer gate, not the last instance) on getting-started, faq, and
  rate-limiting.
- Key the credential-stuffing and API-abuse examples on non-forgeable
  values and caveat the tier and identity header examples.
- Fix the Laravel trusted-proxy source, the Symfony services config and
  env notes and listener probe, and the Mezzio ErrorHandler ordering.
- Add a plain-PHP front controller, repair the First Test step, and
  introduce the key and request concepts for newcomers.
- Drop per-version framing so the docs read as the current 0.5.0 state.
- Normalize dash style throughout.
Tier, role, user-id, and signature-validation values are computed server-side
by your own middleware, so the examples now read them from PSR-7 request
attributes (set via withAttribute) instead of client-supplied headers, which a
caller could forge. Attributes live only on the server-side request object and
never travel on the wire.

Covers dynamic-throttle, rate-limiting, common-attacks, faq, getting-started,
examples, and the fail2ban API-abuse rule. Login-failure markers keep the
header form only for the separate-upstream-service case, with a note to prefer
an attribute when an in-pipeline middleware sets the marker.
A login failure is determined by the application while it handles the request,
so it is signaled after the handler runs via RequestContext::recordFailure(),
the approach the Brute Force Login section already leads with. The
"Fail2Ban on a Request Marker" example relied on a trusted upstream setting an
X-Login-Failed request header before Phirewall, which is contrived and
forgeable, so it is removed. The comprehensive production setup now uses the
never-match filter plus recordFailure() pattern, and the portable-config
builder example swaps the login marker for a honeypot-path fail2ban rule.
The reload()/version-check loop assumed a process that survives many requests,
which is the long-running-worker case (Swoole, RoadRunner, FrankenPHP worker
mode, Octane). Under PHP-FPM every request is a fresh process, so the default
is now a plain per-request load: read the signed ruleset from the store and
build the Config, and a row change takes effect on the next request. The
version-check is kept but demoted to a labeled long-running-worker
optimization.
Presets now ship only universal-signal bundles (scannerBlocking,
sensitivePathBlocking). API rate limiting and login brute-force protection
hardcode an application's own routes (/api, /login), which vary per app, so
they are documented as plain config instead. presets.md gains a
"Route-specific protection" section pointing to Rate Limiting, Dynamic
Throttle, and Brute Force Login, and the two preset tips on the rate-limiting
and fail2ban pages are removed.
v14 is supported too and the range can change; specific versions are not part
of these docs (the flowd/typo3-firewall extension owns that).
@sascha-egerer sascha-egerer merged commit db546f3 into main Jun 9, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant